'use strict';

layui.define(['setter', 'helper'], function(exports) {
  var $ = layui.jquery;
  var element = layui.element;
  var layer = layui.layer;
  var setter = layui.setter;
  var util = layui.helper;
  var isIE = layui.device().ie;

  var MODULE_NAME = 'menubar';

  var $app = $(setter.app);
  var $win = $(window);
  var $doc = $(document);

  var ClassName = {
    SHOW  : 'layui-show',
    THIS  : 'layui-this',
    HOVER : 'is-hover',
    HAS   : 'has-submenu',
    SHRINK: 'layadmin-layout-shrink'
  };

  var Setting = {
    keyId      : 'id',
    keyLabel   : 'label',
    keyChildren: 'children',
    keyPath    : 'href'
  };

  // 图标 https://iconmonstr.com/
  var Icon = {
    'console' : 'layui-icon layui-icon-console',
    'main'    : 'layui-icon layui-icon-home',
    '00004000': 'im im-id-card', // 从业人员
    '00020000': 'im im-car', // 道路客运
    '00060000': 'im im-truck', // 道路货运
    '00070000': 'im im-tools', // 维修管理
    '00080000': 'im im-graduation-hat', // 驾培管理
    '00120000': 'im im-car', // 城市客运
    '00140000': 'im im-shield', // 执法管理
    '00110001': 'im im-store', // 汽车租赁
    '00180000': 'im im-cubes', // 运政综合
    '00000200': 'im im-gear', // 系统管理
    'default' : 'im im-leaf' // 默认
  };

  function renderMenu(data, payload) {
    data = $.isArray(data) ? data : [];
    if (data.length <= 0) return '';
    var level = $.isNumeric(payload.level) ? payload.level : 0;
    var wholeLabel = payload.wholeLabel || '';
    var wholeId = payload.wholeId || '';
    var node = '<div class="layui-side" data-level="' + level + '"><div class="layui-side-scroll"><ul class="layui-nav layui-nav-tree" lay-filter="layadmin-nav-menu-level-' + level + '">';
    var i = 0;
    var len = data.length;
    var item, id, label, path, has;

    for (; i < len; i++) {
      item = data[i];
      id = item[Setting.keyId];
      label = item[Setting.keyLabel];
      path = item[Setting.keyPath];
      has = Boolean(item[Setting.keyChildren] && item[Setting.keyChildren].length > 0);

      node += [
        '<li ' + (path ? 'lay-href="' + path + '"' : '') + 'class="layui-nav-item' + (has ? ' has-submenu' : '') + '" data-index="' + i + '" data-level="' + level + '" data-id="' + id + '" data-label="' + label + '" data-whole-id="' + util.resolvePath(true, wholeId, id) + '" data-whole-label="' + util.resolvePath(true, wholeLabel, label) + '">',
        '<a href="javascript:void(0);">',
        level === 1 ? '<i class="' + (Icon[id] || Icon['default']) + '"></i>' : '',
        '<cite>' + label + '</cite>',
        '</a></li>'
      ].join('');
    }
    node += '</ul></div></div>';

    return node;
  }

  function getMenuById(data, target) {
    data = $.isArray(data) ? data : [];
    if (data.length <= 0) return data;

    var i = 0;
    var len = data.length;
    var item, id, has, children, _data;

    for (; i < len; i++) {
      item = data[i];
      id = item[Setting.keyId];
      children = item[Setting.keyChildren];
      has = Boolean(children && children.length > 0);

      if (id === target) return children;
      if (has) {
        _data = getMenuById(children, target);
        if (_data && _data.length > 0) return _data;
      }
    }

    return [];
  }

  function NavMenu() {
    this.selector = null;
    this.data = null;
    this.startIndex = 1;
    this.delay = 200;
    this.$container = null;
    this.cache = {};
  }

  NavMenu.prototype.render = function(selector, data) {
    data = $.isArray(data) ? data : [];
    this.selector = selector;
    this.$container = $(selector);
    this.data = data;

    if (this.$container.length <= 0) return;

    this.$container.append(renderMenu.call(this, data, { level: this.startIndex }));
    element.render('nav');
    this.bindEvent();
  };

  NavMenu.prototype.bindEvent = function() {
    if (this.$container.length <= 0) return;

    var _this = this;
    var $originSide = _this.$container.children('.layui-side').first().find('.layui-nav.layui-nav-tree');
    var timer;

    this.$container.on('click.' + MODULE_NAME, 'li', function(e) {
      var $this = $(this);

      $this.removeClass(ClassName.THIS);

      if (!$this.hasClass(ClassName.HAS)) {
        _this.$container.find('.layui-side[data-level]:gt(0)').remove();
      }

      setTimeout(function() {
        layer.closeAll('tips');
      }, 500);
    });

    this.$container.on('mouseenter.' + MODULE_NAME, 'li', function(e) {
      var $this = $(this);
      var $link = $this.children('a');
      var $cite = $link.children('cite');

      var payload = $this.data();
      var id = String(payload.id);
      var level = payload.level;
      var wholeId = String(payload.wholeId);
      var wholeLabel = payload.wholeLabel;
      var menu =  _this.cache[id] || getMenuById(_this.data, id);

      _this.cache[id] = menu;

      var isShrink = $app.hasClass(ClassName.SHRINK);
      if (level === 1 && isShrink) {
        $this.data('tips', layer.tips($this.data('label'), $this, {
          tips   : $this.hasClass(ClassName.HAS) ? 1 : 2,
          time   : -1,
          success: function($layer) {
            $this.hasClass(ClassName.HAS) ? $layer.css('margin-left', 5) : $layer.css('margin-top', ($this.height() - $layer.height()) / 2);
          }
        }));
      }

      var mouseenterHandler = function() {
        var $currentSide;
        var $nextSide;
        var style = {};

        $this.addClass(ClassName.HOVER);
        _this.$container.find('.layui-side[data-level]:gt(' + (level - 1) + ')').remove();

        if ($this.hasClass(ClassName.HAS)) {
          _this.$container.append(renderMenu.call(_this, menu, { level: level + 1, wholeId: wholeId, wholeLabel: wholeLabel }));

          $currentSide = _this.$container.find('.layui-side[data-level="' + level + '"]');
          $nextSide = _this.$container.find('.layui-side[data-level="' + (level + 1) + '"]');
          var bottom = $win.height() - $originSide.offset().top - Math.max($originSide.height(), $win.height() * 0.6);

          $nextSide.css('bottom', Math.max(parseFloat($currentSide.css('bottom')), bottom));
          element.render('nav', 'layadmin-nav-menu-level-' + (level + 1));

          style.zIndex = 1000 - level - 1;

          if (!isIE || isIE > 9) {
            style.transform = 'translateX(' + ($currentSide.offset().left + $currentSide.outerWidth() - 1) + 'px)';
          } else {
            style.left = $currentSide.offset().left + $currentSide.outerWidth() - 1;
          }
          $nextSide.css(style);
        } else {
          if (util.textNodeSize($cite.text()) > $link.width()) {
            $this.data('tips', layer.tips($this.data('label'), $this, {
              tips   : 2,
              time   : -1,
              success: function($layer) {
                var marginTop = ($this.height() - $layer.height()) / 2;
                $layer.css('margin-top', marginTop);
              }
            }));
          }
        }
      };

      clearTimeout(timer);
      timer = setTimeout(function() {
        mouseenterHandler();
      }, _this.delay);
    }).on('mouseleave.' + MODULE_NAME, 'li', function(e) {
      var $this = $(this);
      var level = $this.data('level');

      layer.close($this.data('tips'));

      var mouseleaveHandler = function() {
        var $currentSide;
        var $keepSide;

        $this.removeClass(ClassName.HOVER);
        layer.close($this.data('tips'));

        if ($this.hasClass(ClassName.HAS)) {
          $currentSide = _this.$container.find('.layui-side[data-level="' + level + '"]');
          $keepSide = _this.$container.find('.layui-side[data-level]:lt(' + (level - 1) + ')');

          var $target = $(e.target);

          if (!$currentSide.is($target) &&
            !$currentSide.has($target).length > 0 &&
            !$keepSide.is($target) &&
            !$keepSide.has($target).length > 0) {
            _this.$container.find('.layui-side[data-level]:gt(' + (level - 1) + ')').remove();
          }
        }
      };

      clearTimeout(timer);
      timer = setTimeout(function() { mouseleaveHandler() }, _this.delay);
    });

    $doc.on('mouseover.' + MODULE_NAME, function(e) {
      var $flex = $('.layadmin-btn-flexible');
      var $target = $(e.target);

      if (_this.$container.is($target) ||
        _this.$container.has($target).length > 0 &&
        !$flex.is($target)
      ) {
        return;
      }

      clearTimeout(timer);
      timer = setTimeout(function() { _this.$container.find('.layui-side[data-level]:gt(0)').remove() }, _this.delay);
    });
  };

  exports(MODULE_NAME, new NavMenu());
});
